<template>
  <div class="suspend_ball_wrapper" :style="{
			position: dragableRange === 'window' ? 'fixed' : 'absolute',
			...position,
		}">
    <div v-if="dragable" class="suspend_ball" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">
      <div class="slots" :class="[slotsDirectionData]">
        <slot />
      </div>
    </div>
    <div v-else class="suspend_ball">
      <div class="slots" :class="[slotsDirectionData]">
        <slot />
      </div>
    </div>
    <div class="chat-bubble">
      {{ bubbleText }}
    </div>
  </div>
</template>
<script>
export default {
  props: {
    // 是否可拖拽
    dragable: {
      type: Boolean,
      default: true,
    },
    // 拖拽相对于窗口
    dragableRange: {
      type: String,
      default: 'window',
    },
    // 初始位置
    position: {
      type: Object,
      default: function () {
        return {
          left: 'calc(100% - 42px)',
          top: '80%',
        };
      },
    },
    // 是否缩进
    indent: {
      type: Boolean,
      default: false,
    },
    // 缩进延迟时间
    indentDelayTime: {
      type: Number,
      default: 1000,
    },
    // 缩进距离
    indentDistance: {
      type: Number,
      default: 30,
    },
    // 贴边后是否缩进
    indentNearEdge: {
      type: Boolean,
      default: false,
    },
    // 是否需要贴边（在拖动结束后贴边）
    needNearEdge: {
      type: Boolean,
      default: false,
    },
    // 贴边过渡效果
    nearEdgeTransition: {
      type: String,
      default: 'all ease 0.3s',
    },
    // 贴边方向（自动计算或指定）
    nearEdgeDirection: String,
    // 贴边后缩进的延迟时间
    indentNearEdgeDelay: {
      type: Number,
      default: 1000,
    },
    // 插槽方向
    slotsDirection: {
      type: String,
      default: 'right',
    },
  },
  data() {
    return {
      left: 0,
      top: 0,
      touchType: 0, //触摸类型 1拖动悬浮球 0点击悬浮球
      indentTimer: null,
      indentNearEdgeTimer: null,
      slotsDirectionData: 'right',
      bubbleText: '',
    };
  },
  created() {
    this.slotsDirection && (this.slotsDirectionData = this.slotsDirection);
  },
  mounted() {
    if (this.indent && this.indentDelayTime) {
      this.setIndent();
    }
    this.typing('你好，我是心理关爱师，有什么问题你可以问我哦');
  },
  methods: {
    // 打字效果输出
    typing(text) {
      return new Promise((resolve) => {
        let charCount = 0;
        const timer = setInterval(() => {
          if (charCount < text.length) {
            this.bubbleText += text.charAt(charCount);
            charCount++;
          } else {
            clearInterval(timer);
            resolve(); // 解析 Promise，表示完成
          }
        }, 100);
      });
    },
    touchstart(e) {
      const el = this.$el;

      e.preventDefault();
      //触摸类型 1拖动悬浮球 0点击悬浮球
      this.touchType = 0;
      this.$el.style.transition = 'none';
      this.clearAllTimeout();

      //手指按下时的坐标
      const starX = e.touches[0].clientX;
      const starY = e.touches[0].clientY;

      this.starX = starX;
      this.starY = starY;

      //手指相对元素本身位置
      this.distanceX = starX - el.offsetLeft;
      this.distanceY = starY - el.offsetTop;
    },
    touchmove(e) {
      //手指移动到的坐标
      const moveX = e.touches[0].clientX;
      const moveY = e.touches[0].clientY;

      //手指移动距离
      const moveXDistance = moveX - this.starX;
      const moveYDistance = moveY - this.starY;

      //设置位置
      let left = moveX - this.distanceX;
      let top = moveY - this.distanceY;

      //处理点击产生的细微移动
      if (Math.abs(moveXDistance) > 15 || Math.abs(moveYDistance) > 15) {
        this.touchType = 1;
      }

      this.validMove(left, top);
    },
    touchend() {
      if (this.touchType === 0) {
        this.$emit('touchFunc');
      }

      //是否需要缩进
      if (this.needNearEdge) {
        const { self_offsetWidth, self_offsetHeight, parent_offsetWidth, parent_offsetHeight } =
          this.getSelfAndParentOffset();
        const obj = {
          left: parseFloat(this.$el.style.left),
          top: parseFloat(this.$el.style.top),
        };

        obj.right = parent_offsetWidth - obj.left - self_offsetWidth;
        obj.bottom = parent_offsetHeight - obj.top - self_offsetHeight;

        //各方向中最小值
        let minKey = '';

        //计算贴边方向
        if (this.nearEdgeDirection) {
          minKey = this.nearEdgeDirection;
        } else {
          let min = Math.min();
          for (const key in obj) {
            const val = parseFloat(obj[key]);
            if (val < min) {
              min = val;
              minKey = key;
            }
          }
        }

        //设置贴边过渡
        if (this.nearEdgeTransition) {
          this.$el.style.transition = this.nearEdgeTransition;
        }

        //设置贴边
        this.$el.style[minKey] = 0;

        //设置贴边后缩进
        if (this.indentNearEdge) {
          if (this.indentNearEdgeDelay !== 0) {
            clearTimeout(this.indentNearEdgeTimer);

            this.indentNearEdgeTimer = setTimeout(() => {
              this.$el.style[minKey] = -this.indentDistance + 'px';
              this.setOtherDirectionVal(minKey, this.indentDistance);
            }, this.indentNearEdgeDelay);
          } else {
            this.$el.style[minKey] = -this.indentDistance + 'px';
          }
        }

        this.setOtherDirectionVal(minKey);
      }
    },

    //移动
    validMove(left, top) {
      const { self_offsetWidth, self_offsetHeight, parent_offsetWidth, parent_offsetHeight } =
        this.getSelfAndParentOffset();

      if (left + self_offsetWidth > parent_offsetWidth) {
        left = parent_offsetWidth - self_offsetWidth;
      }
      if (top + self_offsetHeight > parent_offsetHeight) {
        top = parent_offsetHeight - self_offsetHeight;
      }
      if (left <= 0) {
        left = 0;
      }
      if (top <= 0) {
        top = 0;
      }

      this.$el.style.left = left + 'px';
      this.$el.style.top = top + 'px';
      this.left = left;
      this.top = top;
      this.right = 'auto';
      this.bottom = 'auto';
    },

    //设置缩进
    setIndent(delayTime) {
      clearTimeout(this.indentTimer);
      this.indentTimer = setTimeout(() => {
        let direction;
        let el = this.$el;
        const positionObj = this.getPositionComputedStyle();
        for (const key in positionObj) {
          if (parseFloat(positionObj[key]) === 0) {
            direction = key;
          }
        }

        el.style[direction] = el.style[direction] - this.indentDistance + 'px';
      }, delayTime || this.indentDelayTime);
    },
    // 获取根节点位置样式
    getPositionComputedStyle() {
      let el = this.$el;
      let style = getComputedStyle(el);
      const positionObj = {
        top: style.top,
        bottom: style.bottom,
        left: style.left,
        right: style.right,
      };
      return positionObj;
    },

    //设置其他方向position值
    setOtherDirectionVal(minKey, indentDistance = 0) {
      const { parent_offsetWidth, parent_offsetHeight, self_offsetWidth, self_offsetHeight } =
        this.getSelfAndParentOffset();

      let slotsDirection = '';

      switch (minKey) {
        case 'left':
          this.$el.style['right'] = parent_offsetWidth - self_offsetWidth + indentDistance + 'px';
          slotsDirection = 'right';
          break;
        case 'right':
          this.$el.style['left'] = parent_offsetWidth - self_offsetWidth + indentDistance + 'px';
          slotsDirection = 'left';
          break;
        case 'top':
          this.$el.style['bottom'] = parent_offsetHeight - self_offsetHeight + indentDistance + 'px';
          slotsDirection = 'bottom';
          break;
        case 'bottom':
          this.$el.style['top'] = parent_offsetHeight - self_offsetHeight + indentDistance + 'px';
          slotsDirection = 'top';
          break;
      }

      //设置插槽方向(未设置slotsDirection则自动判断)
      if (!this.slotsDirection) {
        this.slotsDirectionData = slotsDirection;
      }
    },

    //计算offset值
    getSelfAndParentOffset() {
      const ifwindowRange = this.dragableRange === 'window';
      const parent_offsetWidth = !ifwindowRange ? this.$el.parentNode.offsetWidth : window.innerWidth;
      const parent_offsetHeight = !ifwindowRange ? this.$el.parentNode.offsetHeight : window.innerHeight;
      const self_offsetWidth = this.$el.offsetWidth;
      const self_offsetHeight = this.$el.offsetHeight;
      return {
        parent_offsetWidth,
        parent_offsetHeight,
        self_offsetWidth,
        self_offsetHeight,
      };
    },

    clearAllTimeout() {
      clearTimeout(this.indentTimer);
      clearTimeout(this.indentNearEdgeTimer);
    },
  },
};
</script>
<style lang="scss" scoped>
.suspend_ball_wrapper {
  position: absolute;
  // top: 0;
  // left: 0;
  width: 55px;
  height: 55px;
  border-radius: 50%;
  box-shadow: 0px 4px 20px 0px rgba(47, 128, 237, 0.2);
  z-index: 1000;
  .suspend_ball {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-size: cover;
    background-image: url('~@/assets/images/mindStation/robot_icon.gif');
    .slots {
      position: absolute;
      width: fit-content;
      height: 100%;
      &.right {
        left: calc(100% + 10px);
      }
      &.left {
        right: calc(100% + 10px);
      }
      &.top {
        bottom: calc(100% + 10px);
      }
      &.bottom {
        top: calc(100% + 10px);
      }
    }
  }
  .chat-bubble {
    background-image: url('~@/assets/images/mindStation/chatBubbleBG.png');
    background-size: 178px 79px;
    background-repeat: no-repeat;
    width: 140px;
    height: 47px;
    position: absolute;
    top: -100%;
    left: -305%;
    font-size: 12px;
    padding: 16px 19px;
  }
}
</style>